import { BaseService, CoolCommException } from '@cool-midway/core';
import { Provide } from '@midwayjs/core';
import { InjectEntityModel } from '@midwayjs/typeorm';
import { Repository, QueryRunner } from 'typeorm';
import { PayBalanceEntity } from '../entity/balance';
import { PayBalanceLogEntity } from '../entity/balanceLog';

/**
 * 支付模块-余额服务
 */
@Provide()
export class PayBalanceService extends BaseService {
  @InjectEntityModel(PayBalanceEntity)
  payBalanceEntity: Repository<PayBalanceEntity>;

  @InjectEntityModel(PayBalanceLogEntity)
  payBalanceLogEntity: Repository<PayBalanceLogEntity>;

  /**
   * 获取用户余额
   */
  async getUserBalance(userId: number): Promise<PayBalanceEntity> {
    let balance = await this.payBalanceEntity.findOne({
      where: { userId },
    });

    if (!balance) {
      // 如果用户没有余额记录，创建一个
      balance = new PayBalanceEntity();
      balance.userId = userId;
      balance.availableBalance = 0;
      balance.frozenBalance = 0;
      balance.totalBalance = 0;
      balance.totalRecharge = 0;
      balance.totalConsume = 0;
      balance.lastUpdateTime = new Date();
      balance.version = 0;
      balance.status = 0;
      balance = await this.payBalanceEntity.save(balance);
    }

    return balance;
  }

  /**
   * 增加余额
   */
  async addBalance(
    userId: number,
    amount: number,
    orderId?: number,
    orderNo?: string,
    description?: string,
    businessType?: number,
    queryRunner?: QueryRunner
  ) {
    const manager = queryRunner
      ? queryRunner.manager
      : this.payBalanceEntity.manager;

    // 获取当前余额（使用悲观锁）
    const balance = await manager.findOne(PayBalanceEntity, {
      where: { userId },
    });

    if (!balance) {
      throw new CoolCommException('用户余额记录不存在');
    }

    const beforeBalance = balance.availableBalance;
    const beforeTotalBalance = balance.totalBalance;

    // 更新余额
    balance.availableBalance =
      Number(balance.availableBalance) + Number(amount);
    balance.totalBalance = Number(balance.totalBalance) + Number(amount);
    balance.totalRecharge = Number(balance.totalRecharge) + Number(amount);
    balance.lastUpdateTime = new Date();
    balance.version += 1;

    await manager.save(balance);

    // 记录余额变动日志
    const log = new PayBalanceLogEntity();
    log.userId = userId;
    log.orderId = orderId;
    log.orderNo = orderNo;
    log.changeType = 0; // 充值
    log.changeAmount = amount;
    log.beforeBalance = beforeBalance;
    log.afterBalance = balance.availableBalance;
    log.balanceType = 0; // 可用余额
    log.businessType = businessType || 0;
    log.description = description || '余额充值';
    log.operatorType = 0; // 系统

    await manager.save(log);

    return {
      beforeBalance,
      afterBalance: balance.availableBalance,
      beforeTotalBalance,
      afterTotalBalance: balance.totalBalance,
    };
  }

  /**
   * 扣减余额
   */
  async deductBalance(
    userId: number,
    amount: number,
    orderId?: number,
    orderNo?: string,
    description?: string,
    businessType?: number,
    queryRunner?: QueryRunner
  ) {
    const manager = queryRunner
      ? queryRunner.manager
      : this.payBalanceEntity.manager;

    // 获取当前余额（使用悲观锁）
    const balance = await manager.findOne(PayBalanceEntity, {
      where: { userId },
      lock: { mode: 'pessimistic_write' },
    });

    if (!balance) {
      throw new CoolCommException('用户余额记录不存在');
    }

    if (balance.availableBalance < amount) {
      throw new CoolCommException('余额不足');
    }

    const beforeBalance = balance.availableBalance;
    const beforeTotalBalance = balance.totalBalance;

    // 更新余额
    balance.availableBalance =
      Number(balance.availableBalance) - Number(amount);
    balance.totalBalance = Number(balance.totalBalance) - Number(amount);
    balance.totalConsume = Number(balance.totalConsume) + Number(amount);
    balance.lastUpdateTime = new Date();
    balance.version += 1;

    await manager.save(balance);

    // 记录余额变动日志
    const log = new PayBalanceLogEntity();
    log.userId = userId;
    log.orderId = orderId;
    log.orderNo = orderNo;
    log.changeType = 1; // 消费
    log.changeAmount = amount;
    log.beforeBalance = beforeBalance;
    log.afterBalance = balance.availableBalance;
    log.balanceType = 0; // 可用余额
    log.businessType = businessType || 1;
    log.description = description || '余额消费';
    log.operatorType = 0; // 系统

    await manager.save(log);

    return {
      beforeBalance,
      afterBalance: balance.availableBalance,
      beforeTotalBalance,
      afterTotalBalance: balance.totalBalance,
    };
  }

  /**
   * 冻结余额
   */
  async freezeBalance(
    userId: number,
    amount: number,
    orderId?: number,
    orderNo?: string,
    description?: string,
    operatorId?: number,
    operatorType?: number
  ) {
    const balance = await this.payBalanceEntity.findOne({
      where: { userId },
      lock: { mode: 'pessimistic_write' },
    });

    if (!balance) {
      throw new CoolCommException('用户余额记录不存在');
    }

    if (balance.availableBalance < amount) {
      throw new CoolCommException('可用余额不足');
    }

    const beforeAvailableBalance = balance.availableBalance;
    const beforeFrozenBalance = balance.frozenBalance;

    // 从可用余额转移到冻结余额
    balance.availableBalance =
      Number(balance.availableBalance) - Number(amount);
    balance.frozenBalance = Number(balance.frozenBalance) + Number(amount);
    balance.lastUpdateTime = new Date();
    balance.version += 1;

    await this.payBalanceEntity.save(balance);

    // 记录余额变动日志 - 可用余额减少
    const availableLog = new PayBalanceLogEntity();
    availableLog.userId = userId;
    availableLog.orderId = orderId;
    availableLog.orderNo = orderNo;
    availableLog.changeType = 3; // 冻结
    availableLog.changeAmount = amount;
    availableLog.beforeBalance = beforeAvailableBalance;
    availableLog.afterBalance = balance.availableBalance;
    availableLog.balanceType = 0; // 可用余额
    availableLog.businessType = 5; // 系统调整
    availableLog.description = description || '余额冻结';
    availableLog.operatorId = operatorId;
    availableLog.operatorType = operatorType || 2; // 管理员

    // 记录余额变动日志 - 冻结余额增加
    const frozenLog = new PayBalanceLogEntity();
    frozenLog.userId = userId;
    frozenLog.orderId = orderId;
    frozenLog.orderNo = orderNo;
    frozenLog.changeType = 3; // 冻结
    frozenLog.changeAmount = amount;
    frozenLog.beforeBalance = beforeFrozenBalance;
    frozenLog.afterBalance = balance.frozenBalance;
    frozenLog.balanceType = 1; // 冻结余额
    frozenLog.businessType = 5; // 系统调整
    frozenLog.description = description || '余额冻结';
    frozenLog.operatorId = operatorId;
    frozenLog.operatorType = operatorType || 2; // 管理员

    await this.payBalanceLogEntity.save([availableLog, frozenLog]);

    return balance;
  }

  /**
   * 解冻余额
   */
  async unfreezeBalance(
    userId: number,
    amount: number,
    orderId?: number,
    orderNo?: string,
    description?: string,
    operatorId?: number,
    operatorType?: number
  ) {
    const balance = await this.payBalanceEntity.findOne({
      where: { userId },
      lock: { mode: 'pessimistic_write' },
    });

    if (!balance) {
      throw new CoolCommException('用户余额记录不存在');
    }

    if (balance.frozenBalance < amount) {
      throw new CoolCommException('冻结余额不足');
    }

    const beforeAvailableBalance = balance.availableBalance;
    const beforeFrozenBalance = balance.frozenBalance;

    // 从冻结余额转移到可用余额
    balance.frozenBalance = Number(balance.frozenBalance) - Number(amount);
    balance.availableBalance =
      Number(balance.availableBalance) + Number(amount);
    balance.lastUpdateTime = new Date();
    balance.version += 1;

    await this.payBalanceEntity.save(balance);

    // 记录余额变动日志 - 冻结余额减少
    const frozenLog = new PayBalanceLogEntity();
    frozenLog.userId = userId;
    frozenLog.orderId = orderId;
    frozenLog.orderNo = orderNo;
    frozenLog.changeType = 4; // 解冻
    frozenLog.changeAmount = amount;
    frozenLog.beforeBalance = beforeFrozenBalance;
    frozenLog.afterBalance = balance.frozenBalance;
    frozenLog.balanceType = 1; // 冻结余额
    frozenLog.businessType = 5; // 系统调整
    frozenLog.description = description || '余额解冻';
    frozenLog.operatorId = operatorId;
    frozenLog.operatorType = operatorType || 2; // 管理员

    // 记录余额变动日志 - 可用余额增加
    const availableLog = new PayBalanceLogEntity();
    availableLog.userId = userId;
    availableLog.orderId = orderId;
    availableLog.orderNo = orderNo;
    availableLog.changeType = 4; // 解冻
    availableLog.changeAmount = amount;
    availableLog.beforeBalance = beforeAvailableBalance;
    availableLog.afterBalance = balance.availableBalance;
    availableLog.balanceType = 0; // 可用余额
    availableLog.businessType = 5; // 系统调整
    availableLog.description = description || '余额解冻';
    availableLog.operatorId = operatorId;
    availableLog.operatorType = operatorType || 2; // 管理员

    await this.payBalanceLogEntity.save([frozenLog, availableLog]);

    return balance;
  }

  /**
   * 系统调整余额
   */
  async adjustBalance(
    userId: number,
    amount: number,
    type: 'add' | 'deduct',
    description: string,
    operatorId: number,
    operatorType: number = 2
  ) {
    if (type === 'add') {
      return await this.addBalance(
        userId,
        amount,
        null,
        null,
        description,
        5 // 系统调整
      );
    } else {
      return await this.deductBalance(
        userId,
        amount,
        null,
        null,
        description,
        5 // 系统调整
      );
    }
  }

  /**
   * 获取余额变动记录
   */
  async getBalanceLogs(
    userId: number,
    page: number = 1,
    size: number = 10,
    changeType?: number,
    balanceType?: number
  ) {
    const where: any = { userId };
    if (changeType !== undefined) {
      where.changeType = changeType;
    }
    if (balanceType !== undefined) {
      where.balanceType = balanceType;
    }

    const [list, total] = await this.payBalanceLogEntity.findAndCount({
      where,
      order: { createTime: 'DESC' },
      skip: (page - 1) * size,
      take: size,
    });

    return {
      list,
      total,
      page,
      size,
    };
  }
}
